/*
 * Copyright (C) 2011-2012 Wojciech Dzierżanowski
 * See LICENSE.txt for licensing details.
 */

package wdzierzan.downstream.android;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Build;
import android.os.Environment;
import android.widget.RemoteViews;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;

import wdzierzan.downstream.android.servermanager.ServerManager;
import wdzierzan.downstream.core.DefaultTargetFileFactory;
import wdzierzan.downstream.core.ReceiverThreadRunner;
import wdzierzan.downstream.core.Streamer;
import wdzierzan.downstream.core.StreamerHandler;

/**
 * @author Wojciech Dzierżanowski <wojciech.dzierzanowski@gmail.com>
 */
public class StreamerService extends IntentService {

    private static final Logger logger = Logger.getLogger(StreamerService.class.getName());

    static final String EXTRA_PATH = "path";
    static final int NOTIFICATION_ID = 1;
    static final String ACTION_CANCEL = "cancel";
    static final String ACTION_CLEAR_OK = "clear-ok";
    static final String ACTION_CLEAR_ERROR = "clear-error";

    private Queue<Streamer> streamers;
    private StreamerHandler handler;
    private RemoteViews contentView;
    private Notification notification;
    private NotificationManager notificationManager;

    public StreamerService() {
        super("StreamerService");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        streamers = new LinkedList<Streamer>();
        handler = new StreamerHandler(new DefaultTargetFileFactory(), new ReceiverThreadRunner(), new ProgressReport());
        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }

    @Override
    public void onDestroy() {
        for (Streamer streamer = streamers.poll(); streamer != null; streamer = streamers.poll())
            ServerManager.getInstance().releaseStreamer(streamer);
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (ACTION_CANCEL.equals(intent.getAction())) {
            handler.cancel();
            stopSelf();
            return START_NOT_STICKY;
        }

        Streamer streamer = ServerManager.getInstance().acquireStreamer();
        if (streamer == null) {
            logger.fine("Can't start downloading: no Streamer available. Ignoring Intent.");
            return START_NOT_STICKY;
        }

        streamers.offer(streamer);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (handler.isCanceled())
            return;

        String path = intent.getStringExtra(EXTRA_PATH);
        File file = new File(path);

        notification = new Notification(android.R.drawable.stat_sys_download, getString(R.string.app_name),
                System.currentTimeMillis());
        notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;

        contentView = new RemoteViews(getPackageName(), R.layout.notification);
        contentView.setImageViewResource(R.id.image, android.R.drawable.stat_sys_download);
        contentView.setTextViewText(R.id.title, getString(R.string.downloading, file.getName()));
        notification.contentView = contentView;

        Intent notificationIntent = new Intent(this, FileListActivity.class);
        notificationIntent.setAction(ACTION_CANCEL);
        notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);

        notificationManager.notify(NOTIFICATION_ID, notification);

        WifiManager wifiManager = ((WifiManager) getSystemService(Context.WIFI_SERVICE));
        WifiLock wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, path);

        File destDir = Build.VERSION.SDK_INT >= 8
                ? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
                : new File(Environment.getExternalStorageDirectory(), "Music");

        Streamer streamer = streamers.poll();

        try {
            wifiLock.acquire();
            handler.stream(streamer, ServerManager.STREAM_PORT, path, destDir.getCanonicalPath(),
                    ServerManager.getInstance().getFormat().extension);
            contentView.setTextViewText(R.id.title,
                    getString(R.string.downloading_finished, file.getName()));
            notificationIntent.setAction(ACTION_CLEAR_OK);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Download failed", e);
            contentView.setTextViewText(R.id.title,
                    getString(R.string.downloading_failed, file.getName()));
            notificationIntent.setAction(ACTION_CLEAR_ERROR);
        } finally {
            wifiLock.release();
            ServerManager.getInstance().releaseStreamer(streamer);
            notification.icon = android.R.drawable.stat_sys_download_done;
            if (handler.isCanceled()) {
                notificationManager.cancel(NOTIFICATION_ID);
            } else {
                notification.flags = 0;
                notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
                notificationManager.notify(NOTIFICATION_ID, notification);
            }
        }
    }

    private class ProgressReport implements wdzierzan.downstream.core.ProgressReport {
        private int total;
        private int current;
        private int kBps;

        public void updateProgress(int total, int current) {
            this.total = total;
            this.current = current;
            showProgress();
        }

        public void updateRate(int kBps) {
            this.kBps = kBps;
            showProgress();
        }

        public long getRateUpdatePeriod() {
            return 3000;
        }

        private void showProgress() {
            contentView.setProgressBar(R.id.progressbar, total, current, false);
            contentView.setTextViewText(R.id.progress, "" + current + '/' + total + " @ " + kBps + " kB/s");
            notificationManager.notify(NOTIFICATION_ID, notification);
        }
    }
}
